import { message } from 'ant-design-vue'
import { AxiosRequestConfig, createHttpService, storage } from 'g6-fn'
import { axios, uuid } from 'g6-fn'

import router from '@/router'
import { useUserInfoStore } from '@/store'
import { notFoundCodeMap } from '@/views/not-found/config'

const uidMap = new Map()

export const http = createHttpService(
  {
    baseURL: '/api'
  },
  (config: any) => {
    // 添加uid
    if (config.isAddUid) {
      let uid = undefined
      const key = `${config.method}-${config.url}`
      // key是否存在
      if (!uidMap.has(key)) {
        uid = uuid()
        uidMap.set(key, uid)
      }
      uid = uidMap.get(key)
      config.headers!['RID'] = uid
    }

    // 添加项目唯一标识
    config.headers!['G-Biz-Id'] = 'control'

    // 添加token
    const token = storage.get('token') || ''
    if (token) {
      config.headers!['G-Token'] = token
    }
    return config
  },
  (response: any) => {
    // 是否需要返回所有数据
    if (response.config.isResponseAll) {
      return downFn(response)
    }

    const { data, headers } = response
    const code = response.data?.code || ''
    data.headers = headers

    // 请求成功刷新uid
    const key = `${response.config.method}-${response.config.url}`
    CancelToken.deleteRequest(CancelToken.getKey(response.config))
    if (code === 'SYSTEM-100000' && uidMap.has(key)) {
      uidMap.delete(key)
    }

    // 对code不做统一判断
    if (response.config.noJudgeCode === true) {
      return data
    }

    if (code === 'SYSTEM-100000' && response.config.headers?.['hide-message'] === 'true') {
      return Promise.resolve(data)
    }

    /* code拦截 */
    // 此code代表rid重复，不需要提示，直接返回即可
    if (code === 'SYSTEM-200302') {
      return Promise.reject(data)
    }

    // 此code代表token过期
    if (code === 'GATE-100002') {
      message.error(data.message)
      const { logout } = useUserInfoStore()
      logout()
      return Promise.reject(data)
    }
    if (code !== 'SYSTEM-100000') {
      console.error(`请求 ===》${response.config.url} 出现错误，接口未返回成功code`)
      if (Object.keys(notFoundCodeMap).includes(code)) {
        const { basePath } = notFoundCodeMap[code]
        router.push({
          path: basePath,
          query: { code }
        })
      } else {
        response.config.headers?.['hide-message'] !== 'true' && message.error(data?.message)
      }
      return Promise.reject(data)
    }

    return data
  },
  (err: any) => {
    if (err && err.response) {
      let errorMessage = ''
      if (err.response.data.msg) {
        errorMessage = err.response.data.msg
      } else {
        errorMessage = err.toString()
      }
      switch (err.response.status) {
        case 400:
          err.message = errorMessage
          break
        case 401:
          err.message = '未授权，请登录'
          break
        case 403:
          err.message = '拒绝访问'
          break
        case 404:
          err.message = `请求地址出错: ${err.response.config.url}`
          break
        case 408:
          err.message = '请求超时'
          break
        case 500:
          err.message = '服务器错误，请联系管理员'
          break
        case 501:
          err.message = '服务未实现'
          break
        case 502:
          err.message = '网关错误'
          break
        case 503:
          err.message = '服务不可用'
          break
        case 504:
          err.message = '网关超时'
          break
        case 505:
          err.message = 'HTTP版本不受支持'
          break
        default:
      }
      message.error(err.message)
    }
    return Promise.reject(err) // 返回接口返回的错误信息
  }
)

// 下载blob错误拦截
const downFn = async (response: any) => {
  if (response.data?.type === 'application/json') {
    const blob = response.data
    const res = JSON.parse(await blob.text())
    if (res.code) {
      return Promise.reject(res)
    }
    return response
  }
  return response
}

// 取消请求
export class CancelToken {
  // 存储每个请求的标识
  static requestList = new Map()

  // 白名单（不进行取消请求） 请求方式-接口（例如：get-/menus）
  static whiteList: Array<string> = [
    'post-/spa/data/v1/model-info/presigned',
    'get-/spa/data/v1/model-info/download',
    'get-/cloud/oss/minio/presigned-download',
    'put-/cloud/oss/minio/presigned-upload'
  ]

  // 获取key
  static getKey(config: AxiosRequestConfig): string {
    return `${config.method}-${config.url}`
  }

  // 验证接口是否被加入白名单
  static verifyWhiteList(config: AxiosRequestConfig): boolean {
    const key: string = this.getKey(config)
    return this.whiteList.includes(key)
  }

  // 添加请求
  static addRequest(config: AxiosRequestConfig) {
    const key: string = this.getKey(config)
    if (this.whiteList.includes(key) || config?.headers!['cancelable'] === false) return
    config.cancelToken = new axios.CancelToken(cancel => {
      // 若请求已存在（请求中）则取消上一次的请求
      if (this.requestList.has(key)) {
        // 取消上一次请求
        this.deleteRequest(key)
      } else if (!this.requestList.has(key) && !this.verifyWhiteList(config)) {
        // 请求不存在并且不在白名单
        this.requestList.set(key, cancel)
      }
    })
  }

  // 取消单个请求
  static deleteRequest(key: string) {
    if (this.requestList.has(key)) {
      // 取消请求
      this.requestList.get(key)(key)
      // 删除当前请求
      this.requestList.delete(key)
    }
  }

  // 取消全部请求
  static cencelAllRequest() {
    // 遍历请求列表 全部取消
    for (const [url, cancel] of this.requestList) {
      cancel(url)
    }
    this.requestList.clear()
  }
}
